<script setup lang="ts">
import {useAppStore, useDictStore} from "@/stores";
import {apiLogApi} from "@/api/api-log";
import {
  DataTableBaseColumn,
  DataTableColumns,
  DataTableFilterState,
  DataTableInst,
  FormInst,
  NButton,
  PaginationInfo,
  PaginationProps
} from "naive-ui";
import {ApiLog} from "@/api/api-log/types.ts";
import {copyToClipboard, renderPermission, resetToNull} from "@/utils";

interface PageQuery {
  traceId?: string
  requestMethod?: string
  serverName?: string
  httpStatus?: number
  dateTimeRange?: [string, string]
}

const dictStore = useDictStore();
const appStore = useAppStore();
const pageQuery = reactive<PageQuery>({})
const tableRef = ref<DataTableInst | null>(null)
const tableLoading = ref(false);
const tableData = ref<ApiLog[]>([])
const tableColumns = ref<DataTableColumns<ApiLog>>([
  {title: "traceId", key: "traceId", width: 100, ellipsis: {tooltip: true}, resizable: true},
  {
    title: "服务名称", key: "serverName", resizable: true, align: "center",
    render: row => dictStore.renderTag('server-name', row.serverName),
    filter: true, filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('server-name')
  },
  {title: "用户IP", key: "userIp", resizable: true},
  {
    title: "请求方式", key: "requestMethod", resizable: true, align: "center",
    render: row => dictStore.renderTag('http-method', row.requestMethod),
    filter: true, filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('http-method')
  },
  {title: "请求地址", key: "requestUrl", resizable: true, ellipsis: {tooltip: true}},
  {
    title: "状态码", key: "httpStatus", resizable: true, align: "center",
    render: row => dictStore.renderTag('http-status', row.httpStatus),
    filter: true, filterMultiple: false,
    filterOptions: dictStore.getDictTextOptions('http-status')
  },
  {title: "错误码", key: "errorCode", resizable: true},
  {title: "请求时间", key: "createTime", resizable: true},
  {title: "耗时(ms)", key: "costTime", resizable: true},
  {title: "操作", key: "action", resizable: true, align: "center", render: row => tableActionRender(row)}
])
const tablePagination = reactive<PaginationProps>({
  prefix: (info: PaginationInfo) => {
    return `共 ${info.itemCount} 条记录`
  },
  showSizePicker: true,
  pageSizes: [10, 20, 50, 100],
  itemCount: 0,
  pageCount: 0,
  onChange: (page: number) => {
    tablePagination.page = page
    handlePageQuery()
  },
  onUpdatePageSize: (pageSize: number) => {
    tablePagination.pageSize = pageSize
    tablePagination.page = 1
    handlePageQuery()
  }
})

const drawerDetailShow = ref(false)
const drawerDetailFormModel = reactive<ApiLog>(<ApiLog>{})

const modelShow = ref(false)
const modalFormRef = ref<FormInst | null>()
const modalSubmitLoading = ref(false)

onMounted(() => {
  dictStore.loadDict(['server-name', 'http-method', 'http-status', 'api-error-status'])
  handlePageQuery()
})
const tableActionRender = (row: ApiLog) => {
  return renderPermission(h(NButton, {
    tertiary: true,
    size: 'small',
    onClick: () => handleClickDetail(row)
  }, {default: () => '详情'}), 'api-log:detail')
}
const handlePageQuery = () => {
  tableLoading.value = true;
  const {dateTimeRange, ...rest} = pageQuery
  apiLogApi.page({
    ...rest,
    startTime: dateTimeRange?.[0],
    endTime: dateTimeRange?.[1],
    current: tablePagination.page ?? 1,
    size: tablePagination.pageSize ?? 10
  }).then(res => {
    tableData.value = res.data.records
    tablePagination.itemCount = res.data.total
    tablePagination.pageCount = res.data.pages
  }).finally(() => tableLoading.value = false)
}
const handleClickReset = () => {
  resetToNull(pageQuery)
  tableRef.value?.filter(null)
  handlePageQuery()
}
const handleClickDetail = (row: ApiLog) => {
  apiLogApi.detail(row.id).then(res => {
    Object.assign(drawerDetailFormModel, res.data)
    drawerDetailShow.value = true
  })
}
const handleDrawerClose = () => {
  drawerDetailShow.value = false
  resetToNull(drawerDetailFormModel)
}
const handleClickApiErrorProcess = () => {
  modelShow.value = true
}
const handleClickProcessSubmit = () => {
  modalSubmitLoading.value = true
  apiLogApi.errorHandle({
    id: drawerDetailFormModel.id,
    handlingStatus: drawerDetailFormModel.handlingStatus,
    handlingRemark: drawerDetailFormModel.handlingRemark,
  }).then(res => {
    window.$message?.success(res.message)
    modelShow.value = false
  }).finally(() => modalSubmitLoading.value = false)
}
</script>

<template>
  <n-card>
    <template #header>
      <n-space vertical>
        <n-space>
          <n-input
              v-model:value="pageQuery.traceId" type="text" placeholder="traceId" clearable w100px/>
          <n-date-picker
              clearable
              type="datetimerange"
              :actions="['clear']"
              value-format="yyyy-MM-dd HH:mm:ss"
              v-model:formatted-value="pageQuery.dateTimeRange"
          />
        </n-space>
        <n-space>
          <n-button
              secondary
              @click="handlePageQuery"
              :loading="tableLoading"
              v-p="'api-log:page'"
          >查询
          </n-button>
          <n-button
              secondary
              type="warning"
              @click="handleClickReset"
          >重置
          </n-button>
        </n-space>
      </n-space>
    </template>
    <n-data-table
        remote
        size="small"
        ref="tableRef"
        :loading="tableLoading"
        :columns="tableColumns"
        :data="tableData"
        :pagination="tablePagination"
        @update:filters="(filters: DataTableFilterState, {key}: DataTableBaseColumn) => {
          pageQuery[key] = filters[key]
          handlePageQuery()
        }"
    />
  </n-card>
  <n-drawer
      v-model:show="drawerDetailShow"
      :width="800"
      placement="right"
      :on-after-leave="handleDrawerClose"
      :auto-focus="false"
      :mask-closable="false"
      close-on-esc
  >
    <n-drawer-content closable>
      <template #header>
        <n-space align-center>
          <span>API日志</span>
          <dict-tag v-if="drawerDetailFormModel.handlingStatus != null" dict-code="api-error-status"
                    :dict-value="drawerDetailFormModel.handlingStatus" size="small"/>
        </n-space>
      </template>
      <n-descriptions
          label-placement="left"
          bordered
          size="small"
          :column="3"
          :label-class="'w-100px'"
      >
        <n-descriptions-item
            label="traceId"
            :span="3"
        >
          <n-space>
            <n-tag type="primary">{{ drawerDetailFormModel.traceId }}</n-tag>
            <n-button text vertical-mid @click="copyToClipboard(drawerDetailFormModel.traceId)">
              <template #icon>
                <n-icon>
                  <icon-lucide:copy/>
                </n-icon>
              </template>
            </n-button>
          </n-space>
        </n-descriptions-item>
        <n-descriptions-item label="服务名称" :span="3">
          <dict-tag dict-code="server-name" :dict-value="drawerDetailFormModel.serverName"/>
        </n-descriptions-item>
        <n-descriptions-item label="服务主机" :span="1">{{ drawerDetailFormModel.serverHost }}</n-descriptions-item>
        <n-descriptions-item label="服务IP" :span="1">{{ drawerDetailFormModel.serverIp }}</n-descriptions-item>
        <n-descriptions-item label="用户IP" :span="1">{{ drawerDetailFormModel.userIp }}</n-descriptions-item>
        <n-descriptions-item label="User-Agent" :span="3">{{ drawerDetailFormModel.userAgent }}</n-descriptions-item>
        <n-descriptions-item label="请求方式" :span="1">
          <dict-tag dict-code="http-method" :dict-value="drawerDetailFormModel.requestMethod"/>
        </n-descriptions-item>
        <n-descriptions-item label="请求地址" :span="3">{{ drawerDetailFormModel.requestUrl }}</n-descriptions-item>
        <n-descriptions-item label="请求位置" :span="3">{{ drawerDetailFormModel.requestLocal }}</n-descriptions-item>
        <n-descriptions-item label="请求载体" :span="3">
          <vue-json-pretty
              v-if="drawerDetailFormModel.requestPayload"
              :theme="appStore.darkTheme ? 'dark' : 'light'"
              :data="JSON.parse(drawerDetailFormModel.requestPayload)"
              show-length
              :deep="1"
          />
        </n-descriptions-item>
        <n-descriptions-item label="状态码" :span="1">
          <dict-tag dict-code="http-status" :dict-value="drawerDetailFormModel.httpStatus"/>
        </n-descriptions-item>
        <n-descriptions-item label="错误码" :span="2">{{ drawerDetailFormModel.errorCode }}</n-descriptions-item>
        <n-descriptions-item label="请求时间" :span="3">{{ drawerDetailFormModel.createTime }}</n-descriptions-item>
        <n-descriptions-item label="响应载体" :span="3">
          <vue-json-pretty
              :theme="appStore.darkTheme ? 'dark' : 'light'"
              :data="JSON.parse(drawerDetailFormModel.responsePayload)"
              show-length
              :deep="1"
          />
        </n-descriptions-item>
        <n-descriptions-item label="创建人" :span="1">{{ drawerDetailFormModel.createId }}</n-descriptions-item>
        <n-descriptions-item label="耗时(ms)" :span="2">{{ drawerDetailFormModel.costTime }}</n-descriptions-item>
        <template v-if="drawerDetailFormModel.httpStatus !== 200">
          <n-descriptions-item label="异常类" :span="2">{{ drawerDetailFormModel.exceptionClass }}</n-descriptions-item>
          <n-descriptions-item label="处理备注" :span="3">{{ drawerDetailFormModel.handlingRemark }}
          </n-descriptions-item>
          <n-descriptions-item label="异常信息" :span="3">{{
              drawerDetailFormModel.exceptionMessage
            }}
          </n-descriptions-item>
          <n-descriptions-item label="异常位置" :span="3">{{
              drawerDetailFormModel.exceptionLocal
            }}
          </n-descriptions-item>
          <n-descriptions-item label="异常堆栈" :span="3">{{ drawerDetailFormModel.stackTrace }}</n-descriptions-item>
        </template>
      </n-descriptions>
      <template v-if="drawerDetailFormModel.httpStatus !== 200" #footer>
        <n-button type="info" @click="handleClickApiErrorProcess" v-p="'api-log:error-handle'">处理</n-button>
      </template>
    </n-drawer-content>
  </n-drawer>
  <n-modal
      v-model:show="modelShow"
      w-500px
      preset="card"
      title="处理异常"
      size="large"
  >
    <n-form
        ref="modalFormRef"
        :model="drawerDetailFormModel"
    >
      <n-grid :cols="24">
        <n-form-item-gi :span="24" label="处理状态" path="handlingStatus">
          <n-select
              v-model:value="drawerDetailFormModel.handlingStatus"
              :options="dictStore.getDictTagOptions('api-error-status')"
          />
        </n-form-item-gi>
        <n-form-item-gi :span="24" label="处理备注" path="handlingRemark">
          <n-input type="textarea" v-model:value="drawerDetailFormModel.handlingRemark" placeholder="请输入处理备注"
                   clearable/>
        </n-form-item-gi>
      </n-grid>
    </n-form>
    <template #footer>
      <n-space justify="end">
        <n-button @click="modelShow = false">取消</n-button>
        <n-button type="primary" @click="handleClickProcessSubmit" :loading="modalSubmitLoading">提交</n-button>
      </n-space>
    </template>
  </n-modal>
</template>

<style scoped>

</style>
